package conv

import (
	"encoding/json"
	"fmt"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"golang.org/x/crypto/bcrypt"
	"math"
	"reflect"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

// Int converts `any` to int.
func Int(any interface{}) int {
	if any == nil {
		return 0
	}
	if v, ok := any.(int); ok {
		return v
	}
	return int(Int64(any))
}

// Int8 converts `any` to int8.
func Int8(any interface{}) int8 {
	if any == nil {
		return 0
	}
	if v, ok := any.(int8); ok {
		return v
	}
	return int8(Int64(any))
}

// Int16 converts `any` to int16.
func Int16(any interface{}) int16 {
	if any == nil {
		return 0
	}
	if v, ok := any.(int16); ok {
		return v
	}
	return int16(Int64(any))
}

// Int32 converts `any` to int32.
func Int32(any interface{}) int32 {
	if any == nil {
		return 0
	}
	if v, ok := any.(int32); ok {
		return v
	}
	return int32(Int64(any))
}

// Int64 converts `any` to int64.
func Int64(any interface{}) int64 {
	if any == nil {
		return 0
	}
	switch value := any.(type) {
	case int:
		return int64(value)
	case int8:
		return int64(value)
	case int16:
		return int64(value)
	case int32:
		return int64(value)
	case int64:
		return value
	case uint:
		return int64(value)
	case uint8:
		return int64(value)
	case uint16:
		return int64(value)
	case uint32:
		return int64(value)
	case uint64:
		return int64(value)
	case float32:
		return int64(value)
	case float64:
		return int64(value)
	case bool:
		if value {
			return 1
		}
		return 0
	default:
		var (
			s       = String(value)
			isMinus = false
		)
		if len(s) > 0 {
			if s[0] == '-' {
				isMinus = true
				s = s[1:]
			} else if s[0] == '+' {
				s = s[1:]
			}
		}
		// Hexadecimal
		if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
			if v, e := strconv.ParseInt(s[2:], 16, 64); e == nil {
				if isMinus {
					return -v
				}
				return v
			}
		}
		// Decimal
		if v, e := strconv.ParseInt(s, 10, 64); e == nil {
			if isMinus {
				return -v
			}
			return v
		}
		// Float64
		if valueInt64 := Float64(value); math.IsNaN(valueInt64) {
			return 0
		} else {
			return int64(valueInt64)
		}
	}
}

// Uint converts `any` to uint.
func Uint(any interface{}) uint {
	if any == nil {
		return 0
	}
	if v, ok := any.(uint); ok {
		return v
	}
	return uint(Uint64(any))
}

// Uint8 converts `any` to uint8.
func Uint8(any interface{}) uint8 {
	if any == nil {
		return 0
	}
	if v, ok := any.(uint8); ok {
		return v
	}
	return uint8(Uint64(any))
}

// Uint16 converts `any` to uint16.
func Uint16(any interface{}) uint16 {
	if any == nil {
		return 0
	}
	if v, ok := any.(uint16); ok {
		return v
	}
	return uint16(Uint64(any))
}

// Uint32 converts `any` to uint32.
func Uint32(any interface{}) uint32 {
	if any == nil {
		return 0
	}
	if v, ok := any.(uint32); ok {
		return v
	}
	return uint32(Uint64(any))
}

// Uint64 converts `any` to uint64.
func Uint64(any interface{}) uint64 {
	if any == nil {
		return 0
	}
	switch value := any.(type) {
	case int:
		return uint64(value)
	case int8:
		return uint64(value)
	case int16:
		return uint64(value)
	case int32:
		return uint64(value)
	case int64:
		return uint64(value)
	case uint:
		return uint64(value)
	case uint8:
		return uint64(value)
	case uint16:
		return uint64(value)
	case uint32:
		return uint64(value)
	case uint64:
		return value
	case float32:
		return uint64(value)
	case float64:
		return uint64(value)
	case bool:
		if value {
			return 1
		}
		return 0
	default:
		s := String(value)
		// Decimal
		if v, e := strconv.ParseUint(s, 10, 64); e == nil {
			return v
		}
		// Float64
		if valueFloat64 := Float64(value); math.IsNaN(valueFloat64) {
			return 0
		} else {
			return uint64(valueFloat64)
		}
	}
}

func Float32(any interface{}) float32 {
	if any == nil {
		return 0
	}
	switch value := any.(type) {
	case float32:
		return value
	case float64:
		return float32(value)
	default:
		v, _ := strconv.ParseFloat(String(any), 64)
		return float32(v)
	}
}

func Float64(any interface{}) float64 {
	if any == nil {
		return 0
	}
	switch value := any.(type) {
	case float32:
		return float64(value)
	case float64:
		return value
	default:
		v, _ := strconv.ParseFloat(String(any), 64)
		return v
	}
}

func String(any interface{}) string {
	if any == nil {
		return ""
	}
	switch value := any.(type) {
	case int:
		return strconv.Itoa(value)
	case int8:
		return strconv.Itoa(int(value))
	case int16:
		return strconv.Itoa(int(value))
	case int32:
		return strconv.Itoa(int(value))
	case int64:
		return strconv.FormatInt(value, 10)
	case uint:
		return strconv.FormatUint(uint64(value), 10)
	case uint8:
		return strconv.FormatUint(uint64(value), 10)
	case uint16:
		return strconv.FormatUint(uint64(value), 10)
	case uint32:
		return strconv.FormatUint(uint64(value), 10)
	case uint64:
		return strconv.FormatUint(value, 10)
	case float32:
		return strconv.FormatFloat(float64(value), 'f', -1, 32)
	case float64:
		return strconv.FormatFloat(value, 'f', -1, 64)
	case bool:
		return strconv.FormatBool(value)
	case string:
		return value
	case []byte:
		return string(value)
	case time.Time:
		if value.IsZero() {
			return ""
		}
		return value.String()
	case *time.Time:
		if value == nil {
			return ""
		}
		return value.String()
	default:
		if jsonContent, err := json.Marshal(value); err != nil {
			return fmt.Sprint(value)
		} else {
			return string(jsonContent)
		}
	}
}

// 判断一个变量是否为空
func IsEmpty(value interface{}) bool {
	switch v := value.(type) {
	case nil:
		return true
	case bool:
		return !v
	case int, int8, int16, int32, int64:
		return v == 0
	case uint, uint8, uint16, uint32, uint64, uintptr:
		return v == 0
	case float32, float64:
		return v == 0.0
	case complex64, complex128:
		return v == 0
	case string:
		return len(v) == 0
	case []interface{}:
		return len(v) == 0
	case map[string]interface{}:
		return len(v) == 0
	case []map[string]interface{}:
		return len(v) == 0
	case []string:
		return len(v) == 0
	case chan interface{}:
		return len(v) == 0
	default:
		if reflect.ValueOf(value).Kind() == reflect.Ptr {
			return reflect.ValueOf(value).IsNil()
		}
		return false // 对于其他类型，默认不为空
	}
}

func Slice(any interface{}) []string {
	return StringToSlice(String(any), ",")
}

func GetItemVal(val any, data string) string {
	if val != "" {
		tmp := ToSliceMap(data)
		var name string
		for _, v := range tmp {
			if String(v["val"]) == String(val) {
				name = String(v["key"])
			}
		}
		return name
	} else {
		return ""
	}
}

func GetValByKey(key string, data string) string {
	if key != "" {
		tmp := ToSliceMap(data)
		var val string
		for _, v := range tmp {
			if String(v["key"]) == key {
				val = String(v["val"])
			}
		}
		return val
	} else {
		return ""
	}
}

// 字符窜转驼峰
func ToCamelCase(s string) string {
	split := strings.Split(s, "_")
	for i, str := range split {
		if i == 0 {
			split[i] = str
		} else {
			first := strings.ToUpper(string(str[0]))
			split[i] = first + str[1:]
		}
	}
	return FirstUpper(strings.Join(split, ""))
}

// 字符串首字母大写
func FirstUpper(s string) string {
	if s == "" {
		return ""
	}
	return strings.ToUpper(s[:1]) + s[1:]
}

// 字符串首字母小写
func FirstLower(s string) string {
	if s == "" {
		return ""
	}
	return strings.ToLower(s[:1]) + s[1:]
}

// 加密
func EncryptPassword(password string) string {
	if password == "" {
		return ""
	}
	encryptPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	return string(encryptPassword)
}

// 密码对比
func EqualsPassword(password, encryptPassword string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(encryptPassword), []byte(password))
	return err == nil
}

// 判断切片是否存在某个元素
func IsValueInList(value string, list []string) bool {
	for _, v := range list {
		if v == value {
			return true
		}
	}
	return false
}

// 字符窜转为切片
func StringToSlice(str string, sep string) []string {
	var slice []string
	for _, v := range strings.Split(str, sep) {
		slice = append(slice, v)
	}
	return slice
}

// 切片转字符窜
func SliceToString(array []interface{}) string {
	return strings.Replace(strings.Trim(fmt.Sprint(array), "[]"), " ", ",", -1)
}

// 切片转字符窜
func Join(array []string, step string) string {
	return strings.Join(array, step)
}

// 字符窜转byte
func String2Bytes(s string) []byte {
	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
	bh := reflect.SliceHeader{
		Data: sh.Data,
		Len:  sh.Len,
		Cap:  sh.Len,
	}
	return *(*[]byte)(unsafe.Pointer(&bh))
}

// byte转字符窜
func Bytes2String(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// 获取map key返回数组
func GetMapKeys(m map[string]interface{}) []string {
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	return keys
}

// 二维json字符窜转m对象
func ToSliceMap(jsonStr string) []map[string]interface{} {
	m := make([]map[string]interface{}, 0)
	json.Unmarshal([]byte(jsonStr), &m)
	return m
}

// string转map
func StringToObject(str string) map[string]interface{} {
	var tmp map[string]interface{}
	json.Unmarshal([]byte(str), &tmp)
	return tmp
}

var (
	TimeLayoutDate        = "2006-01-02"
	TimeLayoutDateExt     = "20060102"
	TimeLayoutDateTime    = "2006-01-02 15:04:05"
	TimeLayoutDateTimeExt = "20060102150405"
)

// datetime转时间戳
func UnixTime(date string) int64 {
	if date == "" {
		return 0
	} else {
		ts, _ := time.Parse(TimeLayoutDateTime, date)
		return ts.Unix()
	}
}

// 时间戳转datetime
func DateTime(ts int64) string {
	if ts > 0 {
		return time.Unix(ts, 0).Format(TimeLayoutDateTime)
	} else {
		return ""
	}
}

// 时间戳转datetime
func Date(ts int64) string {
	if ts > 0 {
		return time.Unix(ts, 0).Format(TimeLayoutDate)
	} else {
		return ""
	}
}

func MonthStart() string {
	y, m, _ := time.Now().Date()
	return time.Date(y, m, 1, 0, 0, 0, 0, time.Local).Format(TimeLayoutDateTime)
}

func MonthEnd() string {
	y, m, _ := time.Now().Date()
	return time.Date(y, m+1, 0, 23, 59, 59, 0, time.Local).Format(TimeLayoutDateTime)
}

func TodayStart() time.Time {
	y, m, d := time.Now().Date()
	return time.Date(y, m, d, 0, 0, 0, 0, time.Local)
}

func TodayEnd() time.Time {
	y, m, d := time.Now().Date()
	return time.Date(y, m, d, 23, 59, 59, 1e9-1, time.Local)
}

func NowUnix() int64 {
	return time.Now().Unix()
}

func NowDate() string {
	return time.Now().Format(TimeLayoutDate)
}

func NowDateExt() string {
	return time.Now().Format(TimeLayoutDateExt)
}

func NowDateTime() string {
	return time.Now().Format(TimeLayoutDateTime)
}

func NowDateTimeExt() string {
	return time.Now().Format(TimeLayoutDateTimeExt)
}

func ParseDate(dt string) (time.Time, error) {
	return time.Parse(TimeLayoutDate, dt)
}

func ParseDateTime(dt string) (time.Time, error) {
	return time.Parse(TimeLayoutDateTime, dt)
}

func ParseStringTime(tm, lc string) (time.Time, error) {
	loc, err := time.LoadLocation(lc)
	if err != nil {
		return time.Time{}, err
	}
	return time.ParseInLocation(TimeLayoutDateTime, tm, loc)
}

// mongodb string转objectid 数组
func SliceToObjectIdSlice(id []string) []primitive.ObjectID {
	var ids []primitive.ObjectID
	for _, v := range id {
		objectid, _ := primitive.ObjectIDFromHex(v)
		ids = append(ids, objectid)
	}
	return ids
}

// mongodb string转objectid
func StringToObjectId(id string) primitive.ObjectID {
	objectid, _ := primitive.ObjectIDFromHex(id)
	return objectid
}

// mongodb objectid转string
func ObjectIdToString(id interface{}) string {
	return id.(primitive.ObjectID).Hex()
}

// mongodb排序适配
func Order(value string) int {
	order := -1
	if value == "asc" {
		order = 1
	}
	return order
}
